#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project ：MicInter_IPCamera
@File    ：MQTT_Demo.py
@IDE     ：PyCharm
@Author  ：董文捷
@Date    ：2025/11/5 19:11
'''
import random
import sys
import signal
from threading import Thread
from paho.mqtt import client as mqtt_client

# -------------------------- MQTT 基础配置 --------------------------
# 服务器参数（使用 EMQX 免费公共服务器，无需自建）
BROKER = 'b00001b0.ala.cn-hangzhou.emqxsl.cn'  # Broker 地址
PORT = 8883  # TCP 端口（MQTTS 使用 8883）
SUBSCRIBE_TOPIC = "Android_Get"  # 接收消息的主题
PUBLISH_TOPIC = "Android_Set"  # 发送消息的主题
CLIENT_ID = f'python-mqtt-dual-{random.randint(0, 1000)}'  # 客户端ID（避免重复）

# 用户名和密码（如果需要）
USERNAME = 'username'  # 替换为你的用户名
PASSWORD = 'password'  # 替换为你的密码

# 全局控制标志：用于停止线程和循环
running = True
# 全局 MQTT 客户端实例：方便多线程调用
mqtt_client_instance = None

# -------------------------- 信号处理（优雅退出） --------------------------
def handle_interrupt(signal_num, frame):
    """捕获 Ctrl+C 或 Ctrl+Break 信号，优雅终止程序"""
    global running
    print("\n⚠️  检测到中断信号，准备退出程序...")

    # 停止所有循环和线程
    running = False

    # 断开 MQTT 连接
    if mqtt_client_instance:
        mqtt_client_instance.disconnect()
        print("✅ MQTT 连接已断开")

    print("👋 程序已正常退出")
    sys.exit(0)

# -------------------------- MQTT 连接逻辑 --------------------------
def connect_mqtt():
    """创建并连接 MQTT 客户端，返回客户端实例"""
    global mqtt_client_instance

    def on_connect(client, userdata, flags, rc, properties):
        """连接结果回调函数"""
        if rc == 0:
            print(f"✅ 已成功连接到 MQTT 服务器：{BROKER}:{PORT}")
            # 连接成功后自动订阅接收主题
            client.subscribe(SUBSCRIBE_TOPIC)
            print(f"📥 已订阅接收主题：{SUBSCRIBE_TOPIC}")
        else:
            print(f"❌ 连接 MQTT 服务器失败，错误码：{rc}（错误码 0 表示成功）")
            # 连接失败时终止程序
            running = False

    def on_message(client, userdata, msg):
        """接收消息回调函数（自动触发）"""
        # 解码消息内容（默认 UTF-8 编码）
        msg_content = msg.payload.decode("utf-8")
        print(f"\n📩 收到新消息 | 主题：{msg.topic} | 内容：{msg_content}")
        # 提示用户可继续输入发送（避免与接收消息混淆）
        print("请输入要发送的内容（按回车发送，Ctrl+C 退出）：", end="")

    # 创建 MQTT 客户端（适配 2.0+ 版本的回调 API）
    mqtt_client_instance = mqtt_client.Client(
        client_id=CLIENT_ID,
        callback_api_version=mqtt_client.CallbackAPIVersion.VERSION2
    )

    # 绑定回调函数
    mqtt_client_instance.on_connect = on_connect  # 连接结果回调
    mqtt_client_instance.on_message = on_message  # 接收消息回调

    # 配置 TLS/SSL
    try:
        mqtt_client_instance.tls_set()  # 使用默认的 CA 证书
        mqtt_client_instance.tls_insecure_set(True)  # 忽略证书验证（仅用于测试环境）
    except Exception as e:
        print(f"❌ 配置 TLS/SSL 时发生异常：{str(e)}")
        running = False

    # 设置用户名和密码
    mqtt_client_instance.username_pw_set(USERNAME, PASSWORD)

    # 发起连接
    try:
        mqtt_client_instance.connect(BROKER, PORT)
    except Exception as e:
        print(f"❌ 连接 MQTT 服务器时发生异常：{str(e)}")
        running = False

    return mqtt_client_instance

# -------------------------- 接收消息线程（自动） --------------------------
def start_receive_thread(client):
    """启动接收消息线程（后台运行，自动监听并处理消息）"""
    print("\n🔄 接收消息线程已启动，等待接收数据...")
    # 启动 MQTT 网络循环（非阻塞模式，后台处理接收和心跳）
    client.loop_start()

# -------------------------- 发送消息逻辑（手动） --------------------------
def start_send_loop(client):
    """启动发送消息循环：读取控制台输入，按回车发送"""
    print(f"\n📤 发送消息功能已就绪，发送主题：{PUBLISH_TOPIC}")
    print("请输入要发送的内容（按回车发送，Ctrl+C 退出）：", end="")

    while running:
        try:
            # 读取控制台输入（阻塞，直到用户按回车）
            input_content = input().strip()

            # 若输入为空（只按了回车），跳过发送
            if not input_content:
                print("请输入要发送的内容（按回车发送，Ctrl+C 退出）：", end="")
                continue

            # 发送消息到指定主题
            result = client.publish(PUBLISH_TOPIC, input_content)
            # 检查发送结果（result[0] 为 0 表示发送成功）
            if result[0] == 0:
                print(f"✅ 消息已发送 | 主题：{PUBLISH_TOPIC} | 内容：{input_content}")
            else:
                print(f"❌ 消息发送失败 | 主题：{PUBLISH_TOPIC} | 内容：{input_content}")

            # 提示继续输入
            print("请输入要发送的内容（按回车发送，Ctrl+C 退出）：", end="")

        except Exception as e:
            # 捕获输入过程中的异常（如程序强制退出）
            if running:
                print(f"\n❌ 发送消息时发生异常：{str(e)}")
            break

# -------------------------- 主函数（程序入口） --------------------------
def main():
    # 1. 注册中断信号处理（支持 Ctrl+C 优雅退出）
    signal.signal(signal.SIGINT, handle_interrupt)  # 捕获 Ctrl+C
    signal.signal(signal.SIGBREAK, handle_interrupt)  # 捕获 Ctrl+Break（Windows 系统）

    # 2. 连接 MQTT 服务器
    print(f"🔧 正在初始化 MQTT 客户端...")
    client = connect_mqtt()
    if not running:
        print("❌ MQTT 客户端初始化失败，程序退出")
        return

    # 3. 启动接收消息线程（后台自动接收）
    receive_thread = Thread(target=start_receive_thread, args=(client,), daemon=True)
    receive_thread.start()

    # 4. 启动发送消息循环（前台手动输入）
    start_send_loop(client)

# 程序启动入口
if __name__ == "__main__":
    main()